home *** CD-ROM | disk | FTP | other *** search
- {══════════════════════════════ INTR16.PAS ═══════════════════════════════}
- { ─────────── Turbo 4.0/5.0 subprocess demonstration program ────────── }
- { Copyright (c) 1989 Richard W. Prescott }
- { This Unit contains the assembly code for the basic interrupt routine, }
- { which is installed automatically by the Unit Initialization Code and }
- { is detached automatically by the Unit Exit Code. The original }
- { interrupt vector is stored in the current Code segment to simplify }
- { chaining to the original interrupt routine. The assembly code within }
- { the Procedure IHook traps all Interrupt $16 (BIOS Keyboard Services) }
- { requests and issues a FAR Call via the Pointer variable PascalCode. }
- { PascalCode must be initialized to point to an ordinary (not interrupt) }
- { Procedure which will provide the appropriate interrupt service. }
- {═════════════════════════════════════════════════════════════════════════}
- { This Unit was compiled and assembled using Turbo Pascal Version 4.0 }
- { and TP&Asm Version 2 ß. TP&Asm provides an integrated compile-time }
- { assembler within the Turbo development environment (and the command }
- { line compiler TPC), resulting in an ASSEMBLY Development Environment }
- { which is identical to your PASCAL Development Environment. }
- { }
- { TP&Asm Version 2.0 will be available from me for $49 plus $3 P&H. The }
- { current Beta Test Version 2 ß is available now for $39 plus $3 P&H, }
- { with a free upgrade to 2.0 when it becomes available. }
- { Please see the README file for further information. }
- {═════════════════════════════════════════════════════════════════════════}
-
- Unit Intr16;
-
- interface
-
- {- Public Variables -}
-
- TYPE
- UserRegs = RECORD
- CASE INTEGER OF
- 0: (Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp,Ip,Cs,Flags: WORD);
- 1: (Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh : BYTE);
- END; {UserRegs}
-
- VAR
- ExitSp,UserSP,UserSS: WORD;
- User: ^UserRegs absolute UserSP;
-
- CONST
- PascalCode: Pointer = Nil;
-
-
- {- Public Procedure -}
-
- PROCEDURE IRestore;
-
-
- {- Inline Directives -}
-
- {════════════════════════════════ IReturn ════════════════════════════════}
- { Clear Carry Flag to signal "Return to Caller", restore Stack Pointer }
- { to its value on entry to the Pascal service routine, and issue a Far }
- { Return. This technique permits use of IReturn from within nested }
- { sub-procedures. User registers should be modified before return to }
- { simulate a successful interrupt request. }
- {════════════════════════════════ IReturn ════════════════════════════════}
- PROCEDURE IReturn; {- Inline Directive -}
- Assemble
- Clc ; select Return to Caller
- Mov Sp,ExitSp ; Restore Stack Pointer
- Retf ; .. and return to label "Resume" within IHook
- END; {- IReturn -}
-
- {════════════════════════════════ IChain ═════════════════════════════════}
- { Set Carry Flag to signal "Chain to original Interrupt Vector", restore }
- { Stack Pointer to its value on entry to the Pascal service routine, and }
- { issue a Far Return. This technique permits use of IChain from within }
- { nested sub-procedures. User registers should be preserved. }
- {════════════════════════════════ IChain ═════════════════════════════════}
- PROCEDURE IChain; {- Inline Directive -}
- Assemble
- Stc ; select Chain to original Interrupt Vector
- Mov Sp,ExitSp ; Restore Stack Pointer
- Retf ; .. and return to label "Resume" within IHook
- END; {- IChain -}
-
-
- implementation
-
- {════════════════════════════════ CsData ═════════════════════════════════}
- { The CSDATA construct is used to store data in the current Code Segment. }
- { The original interrupt address Int16Vec must be stored in this Code }
- { Segment to allow Chaining to the original interrupt routine with all of }
- { the User Registers intact. The flag ActiveFlag is stored in the Code }
- { Segment so that it can be inspected before restoring the Turbo DSeg. }
- { CsData Variables are available throughout the current Unit. }
- {════════════════════════════════ CsData ═════════════════════════════════}
- CSDATA
- Int16Vec Dd 0
- ActiveFlag Db 0
- END; {CsData}
-
-
- {═════════════════════════════════ IHook ═════════════════════════════════}
- { This is the assembly portion of the interrupt service routine. }
- { First check ActiveFlag (to permit use of the true BIOS Interrupt $16 }
- { services within the Pascal Code of our service routine). If active, }
- { chain to the original interrupt using an indirect jump to the address }
- { Int16Vec stored in this Code Segment. If not active, save registers, }
- { then restore Ds and issue an indirect call to the address stored in }
- { the Pointer PascalCode. If PascalCode has not been initialized, ignore }
- { the service request and issue a safe "Chain to Original Interrupt". }
- { Within the Pascal service routine, the Calling program registers may }
- { be inspected/modified via the User record, eg "User^.Ax := InChar;" }
- { The Pascal code for the Interrupt Service must end with IReturn/IChain. }
- {═════════════════════════════════ IHook ═════════════════════════════════}
- PROCEDURE IHook; Forward;
- Internal Hook;
- ;- Use INTERNAL to eliminate standard Pascal Startup Code
-
- CODE Segment
-
- IHook PROC NEAR
- Cmp ActiveFlag,FALSE ; check Flag stored in our CS
- IF NE Jmp Int16Vec ; (TP&Asm generates an automatic Cs override)
- Inc ActiveFlag ; Set ActiveFlag := 1 until Resume
-
- WakeUp:
- ;- This Push sequence, read in reverse, must match the
- ;- UserRegs record type defined above:
- Push Bp,Es,Di,Ds,Si,Dx,Cx,Bx,Ax ;- Save User registers
-
- Mov Ax,Seg DATA
- Mov Ds,Ax ; Restore Our Ds
-
- Cmp W PascalCode+2,0 ; Has the PascalCode been installed?
- Stc
- jE Resume ; No, then Chain to original interrupt vector
-
- Mov UserSS,Ss ; Save User Stack Pointer Ss:Sp to permit
- Mov UserSP,Sp ; access to User Regs (eg "User^.Ax")
-
- Mov ExitSp,Sp ; Set Sp value to restore during IChain/IReturn,
- Sub ExitSp,4 ; preserving Return Address of subsequent Far Call
- Call PascalCode ; Call via Pointer to Pascal Service Routine
-
- Resume:
-
- ;- Invoking IChain will return here with the Carry Flag Set
- ;- Invoking IReturn will return here with the Carry Flag Cleared
- ;- The following Mov and Pops do not alter flags
-
- Mov ActiveFlag,0 ; Reset Flag stored in our CSeg
- Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;- Restore User registers
- jNC Return ; State of Carry Flag determines whether to ..
- Chain:
- Jmp Int16Vec ; .. Chain to the original Interrupt $16 Handler
- Return:
- Iret ; .. or Return directly to caller
-
- IHook ENDP
- CODE ENDS
- END {- Internal Hook -}
-
-
-
- {═════════════════════════════════ IInit ═════════════════════════════════}
- { Store the current value of the interrupt $16 vector in the current Code }
- { Segment. Set the new value of the interrupt $16 vector to point to the }
- { INTERNAL Procedure IHook. }
- {═════════════════════════════════ IInit ═════════════════════════════════}
- {- Save and Install New Interrupt 16 -}
- PROCEDURE IInit;
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- ASSEMBLE
-
- ;- Save & Install new interrupt
- Mov Ax,03516 ; Get Interrupt into Es:Bx
- Int 021 ; (Stored in Code Seg to allow Chaining)
- Mov W Int16Vec,Bx ; This Assembly Reference will link in CSDATA
- Mov W Int16Vec+2,Es
-
- Mov Ax,02516 ; Set Interrupt to Ds:Dx
- Push Ds,Cs ; Save DSeg,
- Pop Ds ; point Ds to CSeg
- Mov Dx,Offset IHook ; This Assembly Reference will Link in IHook
- Int 021
- Pop Ds ; Restore Ds to DSeg
-
- END; {Assembly}
- END; {IInit;}
-
-
- {═══════════════════════════════ IRestore ════════════════════════════════}
- { Restore the interrupt $16 vector to the value saved during IInit. }
- {═══════════════════════════════ IRestore ════════════════════════════════}
- PROCEDURE IRestore;
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- ASSEMBLE
- Mov Ax,02516 ; Set Interrupt to Ds:Dx
- Push Ds
- Lds Dx,Int16Vec ; Load Ds:Dx with saved value
- Int 021 ; Restore interrupt vector
- Pop Ds
- END; {Assembly}
- END; {IRestore}
-
-
- {═════════════════════════════════ IExit ═════════════════════════════════}
- { Unit Exit Procedure to automatically detach interrupt system. }
- {═════════════════════════════════ IExit ═════════════════════════════════}
- VAR NextExit: POINTER;
- {$F+} PROCEDURE IExit; {$F-} {- Exit Procedures must use Far Model -}
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- IRestore;
- ExitProc := NextExit;
- END; {IExit}
-
-
- {═════════════════════════════ Initialiation ═════════════════════════════}
- { Automatically install interrupt system. }
- {═════════════════════════════ Initialiation ═════════════════════════════}
- BEGIN
- IInit;
- NextExit := ExitProc;
- ExitProc := @IExit; {- Restore Interrupt 16 on Exit -}
- END.
-